import datetime
import os
import random
import string
import edge_tts
import fastapi
import uvicorn
from fastapi import FastAPI, Request, Response
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from starlette.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles

""" cxl: 18998504636 """

# 存储语音目录
staticPath = "static"

app = FastAPI()
app.debug = True
app.mount("/assets", StaticFiles(directory="templates/assets"), name="assets")
# 设置静态资源目录
app.mount("/static", StaticFiles(directory="static"), name="static")


class CorsMiddleware(CORSMiddleware):
    """
        跨域中间件
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    async def on_request(self, request: Request, scope: str = None):
        response = await super().on_request(request, scope)
        return response

    def on_after_request(self, request: Request, response: Response):
        response.headers["Access-Control-Allow-Origin"] = "*"  # 允许所有源跨域
        response.headers["Access-Control-Allow-Methods"] = "*"  # 允许所有方法跨域
        response.headers["Access-Control-Allow-Headers"] = "*"  # 允许所有头部信息跨域
        response.headers["Access-Control-Allow-Credentials"] = "true"  # 允许携带凭证
        return response


# 将跨域中间件添加到FastAPI应用中
app.add_middleware(CorsMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"],
                   allow_headers=["*"])

templates = Jinja2Templates(directory="templates")

# 语言地区字典
localeDic = {
    "af-ZA": "南非荷兰语（南非）",
    "am-ET": "阿姆哈拉语（埃塞俄比亚）",
    "ar-AE": "阿拉伯语（阿拉伯联合酋长国）",
    "ar-BH": "阿拉伯语（巴林）",
    "ar-DZ": "阿拉伯语（阿尔及利亚）",
    "ar-EG": "阿拉伯语（埃及）",
    "ar-IQ": "阿拉伯语（伊拉克）",
    "ar-JO": "阿拉伯语（约旦）",
    "ar-KW": "阿拉伯语（科威特）",
    "ar-LB": "阿拉伯语（黎巴嫩）",
    "ar-LY": "阿拉伯语（利比亚）",
    "ar-MA": "阿拉伯语（摩洛哥）",
    "ar-OM": "阿拉伯语（阿曼）",
    "ar-QA": "阿拉伯语（卡塔尔）",
    "ar-SA": "阿拉伯语(沙特阿拉伯)",
    "ar-SY": "阿拉伯语（叙利亚）",
    "ar-TN": "阿拉伯语（突尼斯）",
    "ar-YE": "阿拉伯语（也门）",
    "az-AZ": "阿塞拜疆语(拉丁语，阿塞拜疆)",
    "bg-BG": "保加利亚语(保加利亚)",
    "bn-BD": "孟加拉语（孟加拉国）",
    "bn-IN": "孟加拉语（印度）",
    "bs-BA": "波斯尼亚语（波斯尼亚和黑塞哥维那）",
    "ca-ES": "加泰罗尼亚语",
    "cs-CZ": "捷克语(捷克)",
    "cy-GB": "威尔士语（英国）",
    "da-DK": "丹麦语（丹麦）",
    "de-AT": "德语（奥地利）",
    "de-CH": "德语（瑞士）",
    "de-DE": "德语（德国）",
    "el-GR": "希腊语(希腊)",
    "en-AU": "英语（澳大利亚）",
    "en-CA": "英语（加拿大）",
    "en-GB": "英语（英国）",
    "en-HK": "英语（香港特別行政区）",
    "en-IE": "英语（爱尔兰）",
    "en-IN": "英语（印度）",
    "en-KE": "英语（肯尼亚）",
    "en-NG": "英语（尼日利亚）",
    "en-NZ": "英语（新西兰）",
    "en-PH": "英语（菲律宾）",
    "en-SG": "英语（新加坡）",
    "en-TZ": "英语（坦桑尼亚）",
    "en-US": "英语（美国）",
    "en-ZA": "英语（南非）",
    "es-AR": "西班牙语（阿根廷）",
    "es-BO": "西班牙语（玻利维亚）",
    "es-CL": "西班牙语（智利）",
    "es-CO": "西班牙语（哥伦比亚）",
    "es-CR": "西班牙语（哥斯达黎加）",
    "es-CU": "西班牙语（古巴）",
    "es-DO": "西班牙语（多米尼加共和国）",
    "es-EC": "西班牙语（厄瓜多尔）",
    "es-ES": "西班牙语(西班牙)",
    "es-GQ": "西班牙语（赤道几内亚）",
    "es-GT": "西班牙语（危地马拉）",
    "es-HN": "西班牙语（洪都拉斯）",
    "es-MX": "西班牙语(墨西哥)",
    "es-NI": "西班牙（尼加拉瓜）",
    "es-PA": "西班牙语（巴拿马）",
    "es-PE": "西班牙语（秘鲁）",
    "es-PR": "西班牙语（波多黎各）",
    "es-PY": "西班牙语（巴拉圭）",
    "es-SV": "西班牙语（萨尔瓦多）",
    "es-US": "西班牙语（美国）",
    "es-UY": "西班牙语（乌拉圭）",
    "es-VE": "西班牙语（委内瑞拉）",
    "et-EE": "爱沙尼亚语(爱沙尼亚)",
    "eu-ES": "巴斯克语",
    "fa-IR": "波斯语（伊朗）",
    "fi-FI": "芬兰语（芬兰）",
    "fil-PH": "菲律宾语（菲律宾）",
    "fr-BE": "法语（比利时）",
    "fr-CA": "法语（加拿大）",
    "fr-CH": "法语（瑞士）",
    "fr-FR": "法语（法国）",
    "ga-IE": "爱尔兰语（爱尔兰）",
    "gl-ES": "加利西亚语",
    "gu-IN": "古吉拉特语（印度）",
    "he-IL": "希伯来语（以色列）",
    "hi-IN": "印地语（印度）",
    "hr-HR": "克罗地亚语（克罗地亚）",
    "hu-HU": "匈牙利语(匈牙利)",
    "hy-AM": "亚美尼亚语（亚美尼亚）",
    "id-ID": "印度尼西亚语(印度尼西亚)",
    "is-IS": "冰岛语(冰岛)",
    "it-IT": "意大利语（意大利）",
    "ja-JP": "日语（日本）",
    "jv-ID": "爪哇语(拉丁语、印度尼西亚)",
    "ka-GE": "格鲁吉亚语（格鲁吉亚）",
    "kk-KZ": "哈萨克语（哈萨克斯坦）",
    "km-KH": "高棉语(柬埔寨)",
    "kn-IN": "卡纳达语（印度）",
    "ko-KR": "韩语(韩国)",
    "lo-LA": "老挝语(老挝)",
    "lt-LT": "立陶宛语(立陶宛)",
    "lv-LV": "拉脱维亚语(拉脱维亚)",
    "mk-MK": "马其顿语（北马其顿）",
    "ml-IN": "马拉雅拉姆语（印度）",
    "mn-MN": "蒙古语（蒙古）",
    "mr-IN": "马拉地语（印度）",
    "ms-MY": "马来语（马来西亚）",
    "mt-MT": "马耳他语（马耳他）",
    "my-MM": "缅甸语(缅甸)",
    "nb-NO": "书面挪威语（挪威）",
    "ne-NP": "尼泊尔语（尼泊尔）",
    "nl-BE": "荷兰语（比利时）",
    "nl-NL": "荷兰语（荷兰）",
    "pl-PL": "波兰语（波兰）",
    "ps-AF": "普什图语（阿富汗）",
    "pt-BR": "葡萄牙语（巴西）",
    "pt-PT": "葡萄牙语(葡萄牙)",
    "ro-RO": "罗马尼亚语(罗马尼亚)",
    "ru-RU": "俄语（俄罗斯）",
    "si-LK": "僧伽罗语(斯里兰卡)",
    "sk-SK": "斯洛伐克语（斯洛伐克）",
    "sl-SI": "斯洛文尼亚语（斯洛文尼亚）",
    "so-SO": "索马里语（索马里）",
    "sq-AL": "阿尔巴尼亚语（阿尔巴尼亚）",
    "sr-LATN-RS": "塞尔维亚语(拉丁语，塞尔维亚共和国)",
    "sr-RS": "塞尔维亚语(西里尔文，塞尔维亚)",
    "su-ID": "巽他语（印度尼西亚）",
    "sv-SE": "瑞典语（瑞典）",
    "sw-KE": "斯瓦希里语（肯尼亚）",
    "sw-TZ": "斯瓦希里语（坦桑尼亚）",
    "ta-IN": "泰米尔语（印度）",
    "ta-LK": "泰米尔语（斯里兰卡）",
    "ta-MY": "泰米尔语（马来西亚）",
    "ta-SG": "泰米尔语（新加坡）",
    "te-IN": "泰卢固语（印度）",
    "th-TH": "泰语（泰国）",
    "tr-TR": "土耳其语 (Türkiye)",
    "uk-UA": "乌克兰语(乌克兰)",
    "ur-IN": "乌尔都语（印度）",
    "ur-PK": "乌尔都语（巴基斯坦）",
    "uz-UZ": "乌兹别克语(拉丁语，乌兹别克斯坦)",
    "vi-VN": "越南语(越南)",
    "wuu-CN": "中文（吴语，简体）",
    "yue-CN": "中文（粤语，简体）",
    "zh-CN": "中文（普通话，简体）",
    "zh-CN-GUANGXI": "中文（广西口音普通话，简体）",
    "zh-CN-henan": "中文（中原官话河南，简体）",
    "zh-CN-liaoning": "中文（东北官话，简体）",
    "zh-CN-shaanxi": "中文（中原官话陕西，简体）",
    "zh-CN-shandong": "中文（冀鲁官话，简体）",
    "zh-CN-sichuan": "中文（西南普通话，简体）",
    "zh-HK": "中文(粤语，繁体)",
    "zh-TW": "中文（台湾普通话，繁体）",
    "zu-ZA": "祖鲁语（南非）"
}

# 中文语言的声音名称翻译字典
voiceDic = {
    "zh-CN-XiaoxiaoNeural": "晓晓",
    "zh-CN-XiaoyiNeural": "晓伊",
    "zh-CN-YunjianNeural": "云健",
    "zh-CN-YunxiNeural": "云希",
    "zh-CN-YunxiaNeural": "云夏",
    "zh-CN-YunyangNeural": "云扬",
    "zh-CN-liaoning-XiaobeiNeural": "晓北 辽宁",
    "zh-CN-shaanxi-XiaoniNeural": "晓妮 陕西",
    "zh-HK-HiuGaaiNeural": "曉佳",
    "zh-HK-HiuMaanNeural": "曉曼",
    "zh-HK-WanLungNeural": "雲龍",
    "zh-TW-HsiaoChenNeural": "曉臻",
    "zh-TW-HsiaoYuNeural": "曉雨",
    "zh-TW-YunJheNeural": "雲哲"
}

class VoiceItem(BaseModel):
    voice: str
    text: str
    volume: str = "+0%"
    pitch: str = "+0hz"
    rate: str = "+0%"
    fm: str = ".mp3"


def generate_random_string(length):
    """ 随机生成字符串 """
    result = ''.join(random.choices(string.ascii_letters + string.digits, k=length))
    return result


@app.get("/")
async def root(request: fastapi.Request):
    """ 返回首页页面  """
    # 先判断是否有static目录，没有则创建
    if not os.path.exists(staticPath):
        os.makedirs(staticPath)
    return templates.TemplateResponse("index.html", {"request": request})


@app.get("/voice")
async def all_voice():
    """
        获取语音列表并转换格式
    """
    voices = await edge_tts.VoicesManager.create()

    return [{"name": voice["ShortName"],
             "shortName": voiceDic[voice["ShortName"]] if voice["ShortName"] in voiceDic else voice[
                 "ShortName"].replace("Neural", "").replace(voice["Locale"] + "-", ""),
             "lang": voice["Language"], "sex": '女' if voice["Gender"] == 'Female' else '男',
             "loc": voice["Locale"]} for voice in voices.voices]


@app.get("/locale")
def locales():
    """
        返回语言列表
    """
    return localeDic


@app.post("/tts")
async def tts(item: VoiceItem):
    """
        语音合成
    """
    name = generate_random_string(20) + item.fm
    today = datetime.datetime.now().strftime("%Y-%m-%d")
    if not os.path.exists(f"{staticPath}/{today}"):
        os.makedirs(f"{staticPath}/{today}")
    OUTPUT_FILE = f"{staticPath}/{today}/{name}"
    WEBVTT_FILE = f"{staticPath}/{today}/{name}.vtt"

    """输出字幕"""
    communicate = edge_tts.Communicate(text=item.text, voice=item.voice, rate=item.rate, volume=item.volume,
                                       pitch=item.pitch)
    subMaker = edge_tts.SubMaker()
    with open(OUTPUT_FILE, "wb") as file:
        async for chunk in communicate.stream():
            if chunk["type"] == "audio":
                file.write(chunk["data"])
            elif chunk["type"] == "WordBoundary":
                subMaker.create_sub((chunk["offset"], chunk["duration"]), chunk["text"])

    with open(WEBVTT_FILE, "w", encoding="utf-8") as file:
        file.write(subMaker.generate_subs())

    """ 返回语音路径 """
    return today + "/" + name


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)
